View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Set;
26  import java.util.concurrent.ConcurrentHashMap;
27  
28  import org.apache.maven.surefire.booter.Command;
29  import org.apache.maven.surefire.booter.MasterProcessListener;
30  import org.apache.maven.surefire.booter.MasterProcessReader;
31  import org.apache.maven.surefire.common.junit4.JUnit4RunListener;
32  import org.apache.maven.surefire.common.junit4.JUnitTestFailureListener;
33  import org.apache.maven.surefire.common.junit4.Notifier;
34  import org.apache.maven.surefire.common.junit48.FilterFactory;
35  import org.apache.maven.surefire.common.junit48.JUnit48Reflector;
36  import org.apache.maven.surefire.common.junit48.JUnit48TestChecker;
37  import org.apache.maven.surefire.providerapi.AbstractProvider;
38  import org.apache.maven.surefire.providerapi.ProviderParameters;
39  import org.apache.maven.surefire.report.ConsoleLogger;
40  import org.apache.maven.surefire.report.ConsoleOutputCapture;
41  import org.apache.maven.surefire.report.ReporterFactory;
42  import org.apache.maven.surefire.suite.RunResult;
43  import org.apache.maven.surefire.testset.TestListResolver;
44  import org.apache.maven.surefire.testset.TestSetFailedException;
45  import org.apache.maven.surefire.util.RunOrderCalculator;
46  import org.apache.maven.surefire.util.ScanResult;
47  import org.apache.maven.surefire.util.ScannerFilter;
48  import org.apache.maven.surefire.util.TestsToRun;
49  import org.junit.runner.manipulation.Filter;
50  import org.junit.runner.notification.Failure;
51  import org.junit.runner.notification.RunListener;
52  
53  import static org.apache.maven.surefire.junitcore.ConcurrentRunListener.createInstance;
54  import static org.apache.maven.surefire.common.junit4.JUnit4ProviderUtil.generateFailingTests;
55  import static org.apache.maven.surefire.common.junit4.JUnit4RunListenerFactory.createCustomListeners;
56  import static java.util.Collections.unmodifiableCollection;
57  
58  /**
59   * @author Kristian Rosenvold
60   */
61  @SuppressWarnings( { "UnusedDeclaration" } )
62  public class JUnitCoreProvider
63      extends AbstractProvider
64  {
65      private final ClassLoader testClassLoader;
66  
67      private final JUnitCoreParameters jUnitCoreParameters;
68  
69      private final ScannerFilter scannerFilter;
70  
71      private final Collection<RunListener> customRunListeners;
72  
73      private final ProviderParameters providerParameters;
74  
75      private final ScanResult scanResult;
76  
77      private final int rerunFailingTestsCount;
78  
79      private final JUnit48Reflector jUnit48Reflector;
80  
81      private final RunOrderCalculator runOrderCalculator;
82  
83      private final TestListResolver testResolver;
84  
85      private final MasterProcessReader commandsReader;
86  
87      private TestsToRun testsToRun;
88  
89      public JUnitCoreProvider( ProviderParameters providerParameters )
90      {
91          commandsReader = providerParameters.isInsideFork()
92              ? MasterProcessReader.getReader().setShutdown( providerParameters.getShutdown() )
93              : null;
94          this.providerParameters = providerParameters;
95          testClassLoader = providerParameters.getTestClassLoader();
96          scanResult = providerParameters.getScanResult();
97          runOrderCalculator = providerParameters.getRunOrderCalculator();
98          jUnitCoreParameters = new JUnitCoreParameters( providerParameters.getProviderProperties() );
99          scannerFilter = new JUnit48TestChecker( testClassLoader );
100         testResolver = providerParameters.getTestRequest().getTestListResolver();
101         rerunFailingTestsCount = providerParameters.getTestRequest().getRerunFailingTestsCount();
102         String listeners = providerParameters.getProviderProperties().get( "listener" );
103         customRunListeners = unmodifiableCollection( createCustomListeners( listeners ) );
104         jUnit48Reflector = new JUnit48Reflector( testClassLoader );
105     }
106 
107     public Iterable<Class<?>> getSuites()
108     {
109         testsToRun = scanClassPath();
110         return testsToRun;
111     }
112 
113     private boolean isSingleThreaded()
114     {
115         return jUnitCoreParameters.isNoThreading();
116     }
117 
118     public RunResult invoke( Object forkTestSet )
119         throws TestSetFailedException
120     {
121         if ( isRerunFailingTests() && isFailFast() )
122         {
123             throw new TestSetFailedException( "don't enable parameters rerunFailingTestsCount, skipAfterFailureCount" );
124         }
125 
126         final ReporterFactory reporterFactory = providerParameters.getReporterFactory();
127 
128         final ConsoleLogger consoleLogger = providerParameters.getConsoleLogger();
129 
130         Filter filter = jUnit48Reflector.isJUnit48Available() ? createJUnit48Filter() : null;
131 
132         if ( testsToRun == null )
133         {
134             if ( forkTestSet instanceof TestsToRun )
135             {
136                 testsToRun = (TestsToRun) forkTestSet;
137             }
138             else if ( forkTestSet instanceof Class )
139             {
140                 Class<?> theClass = (Class<?>) forkTestSet;
141                 testsToRun = TestsToRun.fromClass( theClass );
142             }
143             else
144             {
145                 testsToRun = scanClassPath();
146             }
147         }
148 
149         Notifier notifier =
150             new Notifier( createRunListener( reporterFactory, consoleLogger ), getSkipAfterFailureCount() );
151 
152         // Add test failure listener
153         JUnitTestFailureListener testFailureListener = new JUnitTestFailureListener();
154         notifier.addListener( testFailureListener );
155 
156         if ( isFailFast() && commandsReader != null )
157         {
158             registerPleaseStopJunitListener( notifier );
159         }
160 
161         try
162         {
163             JUnitCoreWrapper core = new JUnitCoreWrapper( notifier, jUnitCoreParameters, consoleLogger, isFailFast() );
164 
165             if ( commandsReader != null )
166             {
167                 commandsReader.addShutdownListener( new MasterProcessListener()
168                 {
169                     public void update( Command command )
170                     {
171                         testsToRun.markTestSetFinished();
172                     }
173                 } );
174                 commandsReader.awaitStarted();
175             }
176 
177             core.execute( testsToRun, customRunListeners, filter );
178 
179             // Rerun failing tests if rerunFailingTestsCount is larger than 0
180             if ( isRerunFailingTests() )
181             {
182                 for ( int i = 0; i < rerunFailingTestsCount && !testFailureListener.getAllFailures().isEmpty(); i++ )
183                 {
184                     List<Failure> failures = testFailureListener.getAllFailures();
185                     Map<Class<?>, Set<String>> failingTests = generateFailingTests( failures, testClassLoader );
186                     testFailureListener.reset();
187                     final FilterFactory filterFactory = new FilterFactory( testClassLoader );
188                     Filter failingMethodsFilter = filterFactory.createFailingMethodFilter( failingTests );
189                     core.execute( testsToRun, failingMethodsFilter );
190                 }
191             }
192             return reporterFactory.close();
193         }
194         finally
195         {
196             notifier.removeListeners();
197             closeCommandsReader();
198         }
199     }
200 
201     private boolean isRerunFailingTests()
202     {
203         return rerunFailingTestsCount > 0;
204     }
205 
206     private boolean isFailFast()
207     {
208         return providerParameters.getSkipAfterFailureCount() > 0;
209     }
210 
211     private int getSkipAfterFailureCount()
212     {
213         return isFailFast() && !isRerunFailingTests() ? providerParameters.getSkipAfterFailureCount() : 0;
214     }
215 
216     private void closeCommandsReader()
217     {
218         if ( commandsReader != null )
219         {
220             commandsReader.stop();
221         }
222     }
223 
224     private MasterProcessListener registerPleaseStopJunitListener( final Notifier stoppable )
225     {
226         MasterProcessListener listener = new MasterProcessListener()
227         {
228             public void update( Command command )
229             {
230                 stoppable.pleaseStop();
231             }
232         };
233         commandsReader.addSkipNextListener( listener );
234         return listener;
235     }
236 
237     private JUnit4RunListener createRunListener( ReporterFactory reporterFactory, ConsoleLogger consoleLogger )
238         throws TestSetFailedException
239     {
240         if ( isSingleThreaded() )
241         {
242             NonConcurrentRunListener rm = new NonConcurrentRunListener( reporterFactory.createReporter() );
243             ConsoleOutputCapture.startCapture( rm );
244             return rm;
245         }
246         else
247         {
248             final Map<String, TestSet> testSetMap = new ConcurrentHashMap<String, TestSet>();
249 
250             ConcurrentRunListener listener = createInstance( testSetMap, reporterFactory, isParallelTypes(),
251                                                              isParallelMethodsAndTypes(), consoleLogger );
252             ConsoleOutputCapture.startCapture( listener );
253 
254             return new JUnitCoreRunListener( listener, testSetMap );
255         }
256     }
257 
258     private boolean isParallelMethodsAndTypes()
259     {
260         return jUnitCoreParameters.isParallelMethods() && isParallelTypes();
261     }
262 
263     private boolean isParallelTypes()
264     {
265         return jUnitCoreParameters.isParallelClasses() || jUnitCoreParameters.isParallelSuites();
266     }
267 
268     private Filter createJUnit48Filter()
269     {
270         final FilterFactory factory = new FilterFactory( testClassLoader );
271         Filter groupFilter = factory.createGroupFilter( providerParameters.getProviderProperties() );
272         TestListResolver methodFilter = createMethodFilter();
273         boolean onlyGroups = methodFilter == null || methodFilter.isEmpty();
274         return onlyGroups ? groupFilter : factory.and( groupFilter, factory.createMethodFilter( methodFilter ) );
275     }
276 
277     private TestsToRun scanClassPath()
278     {
279         TestsToRun scanned = scanResult.applyFilter( scannerFilter, testClassLoader );
280         return runOrderCalculator.orderTestClasses( scanned );
281     }
282 
283     private TestListResolver createMethodFilter()
284     {
285         return testResolver == null ? null : testResolver.createMethodFilters();
286     }
287 }